package MathTextModeller
{
	import MyDisplayObjects.RectangularTabMenu;
	
	import TaskStructure.LogEvent;
	
	import flash.display.MovieClip;
	import flash.events.MouseEvent;
	import flash.text.*;
	
	/** An object of this class will display a simple number sentence. */
	public class NumberModel extends MovieClip
	{
		// public vars
		public var allowShifting:Boolean;
		
		// private vars
		private var WIDTH:Number, HEIGHT:Number;
		private var _leftNumberTField:TextField, _middleNumberTField:TextField, _rightNumberTField:TextField, leftOperation:TextField, rightOperation:TextField;
		private var fontSize:Number;
		private var operationMenu:RectangularTabMenu, shiftMenu:RectangularTabMenu;
		private var currentlyActiveOperation:TextField, currentlyActiveNumber:TextField;
		
		private var _leftValue:Number = 0, _middleValue:Number = 0, _rightValue:Number = 0;
		private var _leftOperationName:String = "", _rightOperationName:String = "";
		public function get leftValue():Number{if (leftNumberTField==_leftNumberTField){return _leftValue;} else if (leftNumberTField==_middleNumberTField){return _middleValue;} else if (leftNumberTField==_rightNumberTField){return _rightValue;} else {return Number.NaN;}}  
		public function get middleValue():Number{if (middleNumberTField==_leftNumberTField){return _leftValue;} else if (middleNumberTField==_middleNumberTField){return _middleValue;} else if (middleNumberTField==_rightNumberTField){return _rightValue;} else {return Number.NaN;}}  
		public function get rightValue():Number{if (rightNumberTField==_leftNumberTField){return _leftValue;} else if (rightNumberTField==_middleNumberTField){return _middleValue;} else if (rightNumberTField==_rightNumberTField){return _rightValue;} else {return Number.NaN;}}  
		
		public function get leftOperationName():String {if (_leftOperationName=="–"){ return "-";}else{return _leftOperationName;}}
		public function get rightOperationName():String {if (_rightOperationName=="–"){ return "-";}else{return _rightOperationName;}}
		
		public function NumberModel(width:Number, height:Number, allowShifting:Boolean = true)
		{
			this.allowShifting = allowShifting;
			this.WIDTH = width;
			this.HEIGHT = height;
			this.graphics.drawRect(0, 0, width, height);
			fontSize = height-height/4;
			
			_leftNumberTField = new TextField();
			_leftNumberTField.defaultTextFormat = new TextFormat("Arial", fontSize, 0x444444, null, null, null, null, null, "center");
			_leftNumberTField.selectable = false;
			_leftNumberTField.height = HEIGHT;
			_leftNumberTField.width = HEIGHT;
			_leftNumberTField.text = " 0";
			_leftNumberTField.x = WIDTH*1/5-_leftNumberTField.width/2;
			this.addChild(_leftNumberTField);
			if (allowShifting) _leftNumberTField.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverNumber);
			
			_middleNumberTField = new TextField();
			_middleNumberTField.defaultTextFormat = new TextFormat("Arial", fontSize, 0x444444, null, null, null, null, null, "center");
			_middleNumberTField.selectable = false;
			_middleNumberTField.height = HEIGHT;
			_middleNumberTField.width = HEIGHT
			_middleNumberTField.text = " 0";	
			_middleNumberTField.x = (WIDTH - HEIGHT)/2;
			this.addChild(_middleNumberTField);
			if (allowShifting) _middleNumberTField.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverNumber);
			
			_rightNumberTField = new TextField();
			_rightNumberTField.defaultTextFormat = new TextFormat("Arial", fontSize, 0x444444, null, null, null, null, null, "center");
			_rightNumberTField.selectable = false;
			_rightNumberTField.height = HEIGHT;
			_rightNumberTField.width = HEIGHT
			_rightNumberTField.text = " 0";	
			_rightNumberTField.x =  WIDTH*4/5-_leftNumberTField.width/2;
			this.addChild(_rightNumberTField);	
			if (allowShifting) _rightNumberTField.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverNumber);
			
			// operations
			leftOperation = new TextField();
			leftOperation.defaultTextFormat = new TextFormat("Arial", fontSize*2/4, 0x444444, null, null, null, null, null, "center");
			leftOperation.selectable = false;
			leftOperation.height = HEIGHT/2;
			leftOperation.width = HEIGHT/2;
			leftOperation.text = " ";	
			leftOperation.border = true;
			leftOperation.borderColor = 0x888888;
			leftOperation.x = WIDTH/3 - leftOperation.width/2;
			leftOperation.y = (HEIGHT)/4;
			leftOperation.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverOperation);
			this.addChild(leftOperation);		
			
			// operations
			rightOperation = new TextField();
			rightOperation.defaultTextFormat = new TextFormat("Arial", fontSize*2/4, 0x444444, null, null, null, null, null, "center");
			rightOperation.selectable = false;
			rightOperation.height = HEIGHT/2;
			rightOperation.width = HEIGHT/2;
			rightOperation.text = " ";	
			rightOperation.border = true;
			rightOperation.borderColor = 0x888888;
			rightOperation.x = WIDTH*2/3 - leftOperation.width/2;
			rightOperation.y = (HEIGHT)/4;
			rightOperation.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverOperation);
			this.addChild(rightOperation);		
		}
		
		////////////////////////////////////////////// FUNCTIONS FOR NUMBERS ///////////////////////////////////////////////
		/** Increase value on left side of screen. */
		public function increaseLeft(x:Number):void
		{
			_leftValue += x;
			if (_leftValue < 10){ _leftNumberTField.text = String(" " +_leftValue);} 
			else { _leftNumberTField.text = String(_leftValue); }
		}
		
		/** Increase value on middle side of screen. */
		public function increaseMiddle(x:Number):void
		{
			_middleValue += x;
			if (_middleValue < 10){ _middleNumberTField.text = String(" " +_middleValue);}	
			else { _middleNumberTField.text = String(_middleValue); }
		}
		
		/** Increase value on right side of screen. */
		public function increaseRight(x:Number):void
		{
			_rightValue += x;
			if (_rightValue < 10){ _rightNumberTField.text = String(" " +_rightValue);}	
			else { _rightNumberTField.text = String(_rightValue); }
		}
		
		/** Gettting numerical values must be done by comparing x values in case of shifting */
		public function get leftNumberTField():TextField
		{
			if (Math.min(_leftNumberTField.x, Math.min(_middleNumberTField.x, _rightNumberTField.x)) == _leftNumberTField.x)
			{
				return _leftNumberTField;
			} else if (Math.min(_leftNumberTField.x, Math.min(_middleNumberTField.x, _rightNumberTField.x)) == _middleNumberTField.x)
			{
				return _middleNumberTField;
			} else if (Math.min(_leftNumberTField.x, Math.min(_middleNumberTField.x, _rightNumberTField.x)) == _rightNumberTField.x)
			{
				return _rightNumberTField;
			} else 
			{
				return null;
			}
		}
		public function get middleNumberTField():TextField 
		{
			if (Math.min(_leftNumberTField.x, Math.min(_middleNumberTField.x, _rightNumberTField.x)) != _leftNumberTField.x && Math.max(_leftNumberTField.x, Math.max(_middleNumberTField.x, _rightNumberTField.x)) != _leftNumberTField.x)
			{
				return _leftNumberTField;
			} else if (Math.min(_leftNumberTField.x, Math.min(_middleNumberTField.x, _rightNumberTField.x)) != _middleNumberTField.x && Math.max(_leftNumberTField.x, Math.max(_middleNumberTField.x, _rightNumberTField.x)) != _middleNumberTField.x)
			{
				return _middleNumberTField;
			} else if (Math.min(_leftNumberTField.x, Math.min(_middleNumberTField.x, _rightNumberTField.x)) != _rightNumberTField.x && Math.max(_leftNumberTField.x, Math.max(_middleNumberTField.x, _rightNumberTField.x)) != _rightNumberTField.x)
			{
				return _rightNumberTField;
			} else 
			{
				return null;
			}
		}
		public function get rightNumberTField():TextField
		{
			if (Math.max(_leftNumberTField.x, Math.max(_middleNumberTField.x, _rightNumberTField.x)) == _leftNumberTField.x)
			{
				return _leftNumberTField;
			} else if (Math.max(_leftNumberTField.x, Math.max(_middleNumberTField.x, _rightNumberTField.x)) == _middleNumberTField.x)
			{
				return _middleNumberTField;
			} else if (Math.max(_leftNumberTField.x, Math.max(_middleNumberTField.x, _rightNumberTField.x)) == _rightNumberTField.x)
			{
				return _rightNumberTField;
			} else 
			{
				return null;
			}
		}
		
		////////////////////////////////////////////// FUNCTIONS FOR OPERATIONS ///////////////////////////////////////////////
		
		/** When user places mouse over operation pop up menu to allow selection of operation */
		private function handleMouseOverOperation (event:MouseEvent):void
		{
			if (operationMenu == null)
			{
				event.currentTarget.removeEventListener(MouseEvent.MOUSE_OVER, handleMouseOverOperation);	
				currentlyActiveOperation = TextField(event.currentTarget);
				operationMenu = new RectangularTabMenu(event.currentTarget.width*2, leftOperation.height/2, new Array("+", "–", "="), 3, 1);
				operationMenu.x = event.currentTarget.x + (event.currentTarget.width - operationMenu.width)/2;
				operationMenu.y = event.currentTarget.y + event.currentTarget.height;
				operationMenu.addEventListener(MouseEvent.CLICK, handleClickOperation);
				this.addChild(operationMenu);
				this.graphics.beginFill(0xFFFFFF, .5);
				this.graphics.drawRect(0, 0, WIDTH, Math.max(HEIGHT, HEIGHT-operationMenu.y+operationMenu.height));
				this.graphics.endFill();
				// add a listener to this for mouse out
				//operationMenu.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverOperationMenu);		
				this.addEventListener(MouseEvent.MOUSE_OUT, handleMouseOutOperation);	
			}
		}
		private function handleMouseOutOperation (event:MouseEvent):void
		{
			// we don't want to handle an out of this textfield, because then we'll never touch the operation menu
			if (event.target != currentlyActiveOperation)
			{
				this.graphics.clear();
				this.removeEventListener(MouseEvent.MOUSE_OUT, handleMouseOutOperation);	
				operationMenu.removeEventListener(MouseEvent.CLICK, handleClickOperation);
				this.removeChild(operationMenu);
				operationMenu = null;
				currentlyActiveOperation.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverOperation);	
				currentlyActiveOperation = null;
			}
		}
		
		/** When user clicks on an operation on the menu update the textfield, remove the operation menu */
		private function handleClickOperation (event:MouseEvent):void
		{
			if (currentlyActiveOperation == leftOperation)
			{
				_leftOperationName = operationMenu.selectedTabName;
				leftOperation.text = _leftOperationName;
				this.dispatchEvent(new LogEvent(LogEvent.OPERATION_SELECTED, leftOperation.text, "left", leftOperation.x, leftOperation.y));
			} else if (currentlyActiveOperation == rightOperation)
			{
				_rightOperationName = operationMenu.selectedTabName;
				rightOperation.text = _rightOperationName;	
				this.dispatchEvent(new LogEvent(LogEvent.OPERATION_SELECTED, rightOperation.text, "right", rightOperation.x, rightOperation.y));
			} 
			if (this.hasEventListener(MouseEvent.MOUSE_OUT)) this.removeEventListener(MouseEvent.MOUSE_OUT, handleMouseOutOperation);	
			operationMenu.removeEventListener(MouseEvent.CLICK, handleClickOperation);
			
			this.graphics.clear();
			this.removeChild(operationMenu);
			operationMenu = null;
			currentlyActiveOperation.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverOperation);	
			currentlyActiveOperation = null;
		}		
		////////////////////////////////////////////// FUNCTIONS FOR NUMBER SHIFTING  ///////////////////////////////////////////////
		
		/** When user places mouse over operation pop up menu to allow selection of operation */
		private function handleMouseOverNumber (event:MouseEvent):void
		{
			if (operationMenu == null)
			{
				event.currentTarget.removeEventListener(MouseEvent.MOUSE_OVER, handleMouseOverNumber);	
				currentlyActiveNumber = TextField(event.currentTarget);
				shiftMenu = new RectangularTabMenu(event.currentTarget.width*2, leftOperation.height/2, new Array("<<", ">>"), 2, 1);
				shiftMenu.x = event.currentTarget.x + (event.currentTarget.width - shiftMenu.width)/2;
				shiftMenu.y = event.currentTarget.y + event.currentTarget.height - shiftMenu.height;
				shiftMenu.addEventListener(MouseEvent.CLICK, handleClickNumber);
				this.addChild(shiftMenu);
				this.graphics.beginFill(0xFFFFFF, .5);
				this.graphics.drawRect(0, 0, WIDTH, Math.max(HEIGHT, HEIGHT-shiftMenu.y+shiftMenu.height));
				this.graphics.endFill();
				// add a listener to this for mouse out
				//operationMenu.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverOperationMenu);		
				this.addEventListener(MouseEvent.MOUSE_OUT, handleMouseOutNumber);	
			}
		}
		private function handleMouseOutNumber (event:MouseEvent):void
		{
			// we don't want to handle an out of this textfield, because then we'll never touch the operation menu
			if (event.target != currentlyActiveNumber)
			{
				this.graphics.clear();
				this.removeEventListener(MouseEvent.MOUSE_OUT, handleMouseOutNumber);	
				shiftMenu.removeEventListener(MouseEvent.CLICK, handleClickNumber);
				this.removeChild(shiftMenu);
				shiftMenu = null;
				currentlyActiveNumber.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverNumber);	
				currentlyActiveNumber = null;
			}
		}
		
		/** When user clicks on an operation on the menu update the textfield, remove the operation menu */
		private function handleClickNumber (event:MouseEvent):void
		{
			if (currentlyActiveNumber == leftNumberTField)
			{
				if (shiftMenu.selectedTabName == "<<")
				{ // trade left with right
					this.dispatchEvent(new LogEvent(LogEvent.NUMBERS_SWITCHED, String(leftValue), "left", leftNumberTField.x, leftNumberTField.y, String(rightValue), "right", rightNumberTField.x, rightNumberTField.y));
					switchPlaces(leftNumberTField, rightNumberTField);
				} else if (shiftMenu.selectedTabName == ">>")
				{ // trade left with middle
					this.dispatchEvent(new LogEvent(LogEvent.NUMBERS_SWITCHED, String(leftValue), "left", leftNumberTField.x, leftNumberTField.y, String(middleValue), "middle", middleNumberTField.x, middleNumberTField.y));
					switchPlaces (leftNumberTField, middleNumberTField);
				} 				
			} else if (currentlyActiveNumber == middleNumberTField)
			{
				if (shiftMenu.selectedTabName == "<<")
				{ // trade middle with left
					this.dispatchEvent(new LogEvent(LogEvent.NUMBERS_SWITCHED, String(middleValue), "middle", middleNumberTField.x, middleNumberTField.y, String(leftValue), "left", leftNumberTField.x, leftNumberTField.y));
					switchPlaces(middleNumberTField, leftNumberTField);
				} else if (shiftMenu.selectedTabName == ">>")
				{ // trade middle with right
					this.dispatchEvent(new LogEvent(LogEvent.NUMBERS_SWITCHED, String(middleValue), "middle", middleNumberTField.x, middleNumberTField.y, String(rightValue), "right", rightNumberTField.x, rightNumberTField.y));
					switchPlaces (middleNumberTField, rightNumberTField);
				} 	
			} else if (currentlyActiveNumber == rightNumberTField)
			{
				if (shiftMenu.selectedTabName == "<<")
				{ // trade middle with right
					this.dispatchEvent(new LogEvent(LogEvent.NUMBERS_SWITCHED, String(rightValue), "right", rightNumberTField.x, rightNumberTField.y, String(middleValue), "middle", middleNumberTField.x, middleNumberTField.y));
					switchPlaces(rightNumberTField,middleNumberTField);
				} else if (shiftMenu.selectedTabName == ">>")
				{ // trade left with right
					this.dispatchEvent(new LogEvent(LogEvent.NUMBERS_SWITCHED, String(rightValue), "right", rightNumberTField.x, rightNumberTField.y, String(leftValue), "left", leftNumberTField.x, leftNumberTField.y));
					switchPlaces (rightNumberTField, leftNumberTField);
				} 	
			} 
			if (this.hasEventListener(MouseEvent.MOUSE_OUT)) this.removeEventListener(MouseEvent.MOUSE_OUT, handleMouseOutNumber);	
			shiftMenu.removeEventListener(MouseEvent.CLICK, handleClickNumber);
			
			this.graphics.clear();
			this.removeChild(shiftMenu);
			shiftMenu = null;
			currentlyActiveNumber.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOverNumber);	
			currentlyActiveNumber = null;
		}	
		
		private function switchPlaces (tfield1:TextField, tfield2:TextField):void
		{
			var tx:Number = tfield1.x;
			var ty:Number = tfield1.y;
			tfield1.x = tfield2.x;
			tfield1.x = tfield2.x;
			tfield2.x = tx;
			tfield2.y = ty;
		}
	}	
}